 /** ------------------------------------------------------------------------
    File        : LifecycleContext
    Purpose     : 
    Syntax      : 
    Description : 
    @author pjudge
    Created     : Wed Mar 03 10:03:26 EST 2010
    Notes       : 
  ---------------------------------------------------------------------- */
routine-level on error undo, throw.

using OpenEdge.Core.InjectABL.Lifecycle.ILifecycleContext.
using OpenEdge.Core.InjectABL.Lifecycle.LifecycleContext.
using OpenEdge.Core.InjectABL.ICache.
using OpenEdge.Core.InjectABL.Lifecycle.IPipeline.
using OpenEdge.Core.InjectABL.Lifecycle.IProvider.
using OpenEdge.Core.InjectABL.Binding.IBinding.
using OpenEdge.Core.InjectABL.IKernel.

using OpenEdge.Lang.Collections.ICollection.
using OpenEdge.Lang.Collections.Collection.
using OpenEdge.Lang.Assert.
using Progress.Lang.Object.

class OpenEdge.Core.InjectABL.Lifecycle.LifecycleContext
        implements ILifecycleContext:
    
    /** Gets the kernel that is driving the activation. */
    define public property Kernel as IKernel no-undo get. private set.
    
    /** Gets the Binding */
    define public property Binding as IBinding no-undo get. private set.

    /** Gets the parameters that were passed to manipulate the activation process. */
    define public property Arguments as ICollection no-undo get. private set.

    /** Gets or sets the cache component. */
    define public property Cache as ICache no-undo get. private set.

    /** Gets or sets the pipeline component. */
    define public property Pipeline as IPipeline no-undo get. private set.

    /** Initializes a new instance of the <see cref="Context"/> class.
        @param kernel The kernel managing the resolution.
        @param request The context's Request:
        @param binding The context's Binding:
        @param cache The cache component.
        @param planner The planner component.
        @param pipeline The pipeline component. */
    constructor public LifecycleContext(poKernel as IKernel,
                                        poBinding as IBinding,
                                        poPipeline as IPipeline,
                                        poCache as ICache):
        
        Assert:ArgumentNotNull(poKernel, "kernel").
        Assert:ArgumentNotNull(poBinding, "binding").
        Assert:ArgumentNotNull(poPipeline, "pipeline").
        Assert:ArgumentNotNull(poCache, "cache").
        
        assign Kernel = poKernel
               Binding = poBinding
               /* (Deep) Clone the arguments, since we may mess with them on our travels here. */
               Arguments = cast(poBinding:Arguments:Clone(), ICollection)
               Pipeline = poPipeline
               Cache = poCache.
    end constructor.
    
    /** Gets the scope for the context that "owns" the instance activated therein.
        We don't store a reference for it since we want to be able to allow garbage 
        collection to clean it up. 
        
        @return The object that acts as the scope.
     */
    method public Object GetScope():
        return Binding:GetScope(this-object).
    end method.

    /** Gets the provider that should be used to create the instance for this context.
        @return The provider that should be used.
     */
    method public IProvider GetProvider():
        return Binding:GetProvider().
    end method.
    
    /** Resolves the instance associated with this context.
        
        @return The resolved instance.  */
    method public Object Resolve():
        define variable oInstance as Object no-undo.
        
        if Binding:TargetType:IsInterface() then
            oInstance = Kernel:Get(Binding:TargetType).
        else
        do:
            oInstance = Cache:TryGet(this-object).
            if valid-object(oInstance) then
                return oInstance.
            
            /* This will perform any constructor injection, via the provider. */
            oInstance = GetProvider():Create(this-object).
            
            /* Transient object aren't cached */
            if valid-object(GetScope()) then
                Cache:Remember(this-object, oInstance).
            
            /* Activation may have method and/or property injection */
            Pipeline:Activate(this-object, oInstance).
        end.
        
        return oInstance.
    end method.
    
    method override public Object Clone():
        define variable oClone as ILifecycleContext no-undo.
        
        oClone = new LifecycleContext(this-object:Kernel,
                                      this-object:Binding,
                                      this-object:Pipeline,
                                      this-object:Cache).
        return oClone.
    end method.
    
end class.
